use std::collections::VecDeque;

use async_trait::async_trait;
use clap::Parser;

use crate::commands::commands::Command;
use crate::models::models::command::CommandState;
use crate::runtime::error::MagicBoxError;
use crate::runtime::response::Code;
use crate::runtime::result::MagicBoxResult;
use crate::utils::command;

#[derive(Debug, Default, Clone, Parser)]
#[clap(disable_help_flag = true)]
struct Args {
    // 尾数位数
    #[arg(short = 'f', long = "fix", default_value_t = 2)]
    fix: usize,
    // 中缀计算式
    value: Vec<String>,
}

#[derive(Debug, Clone, Default)]
pub(crate) struct CalcCommand {}

#[async_trait]
impl Command for CalcCommand {
    async fn execute(&self, command: crate::models::models::command::Command) -> crate::models::models::command::Command {
        let args = command::parse_command_args::<Args>(command.args.as_str());
        if args.is_err() {
            return self.save_command_output(command, CommandState::Failed, args.unwrap_err().to_string());
        }

        let args = args.unwrap();
        let rpn = self.infix_to_postfix(args.value.join("").as_str());
        if rpn.is_err() {
            return self.save_command_output(command, CommandState::Failed, rpn.unwrap_err().to_string());
        }

        let rpn = rpn.unwrap();
        let result = self.calc_postfix_value(&rpn);
        if result.is_err() {
            return self.save_command_output(command, CommandState::Failed, result.unwrap_err().to_string());
        }

        self.save_command_output(command, CommandState::Success, format!("{:.fix$}", result.unwrap(), fix = args.fix))
    }
}

impl CalcCommand {
    /// 计算后缀表达式的值
    fn calc_postfix_value(&self, value: &Vec<String>) -> MagicBoxResult<f64> {
        let mut output = VecDeque::<f64>::new();

        for str in value {
            match str.as_str() {
                "+" => {
                    let a = output.pop_back().unwrap();
                    let b = output.pop_back().unwrap();
                    log::debug!("{} + {} = {}", a, b, a + b);

                    output.push_back(a + b)
                }
                "-" => {
                    let a = output.pop_back().unwrap();
                    let b = output.pop_back().unwrap();
                    log::debug!("{} - {} = {}", a, b, b - a);

                    output.push_back(b - a)
                }
                "*" => {
                    let a = output.pop_back().unwrap();
                    let b = output.pop_back().unwrap();
                    log::debug!("{} * {} = {}", a, b, a * b);

                    output.push_back(a * b)
                }
                "/" => {
                    let a = output.pop_back().unwrap();
                    let b = output.pop_back().unwrap();
                    log::debug!("{} / {} = {}", a, b, b / a);

                    output.push_back(b / a)
                }
                "^" => {
                    let a = output.pop_back().unwrap();
                    let b = output.pop_back().unwrap();
                    log::debug!("{} ^ {} = {}", a, b, b.powf(a));

                    output.push_back(b.powf(a))
                }
                _ => {
                    output.push_back(str.parse::<f64>().unwrap())
                }
            }
        }

        Ok(output.pop_front().unwrap())
    }
}

impl CalcCommand {
    /// 定义操作符优先级
    fn precedence(&self, op: char) -> MagicBoxResult<i32> {
        match op {
            '+' | '-' => Ok(1),
            '*' | '/' => Ok(2),
            '^' => Ok(3), // 示例中包含指数运算符
            _ => Err(MagicBoxError::new(Code::ParameterError, format!("不支持的运算符: {}", op).as_str())),
        }
    }

    /// 判断是否是操作符
    fn is_operator(&self, ch: char) -> bool {
        matches!(ch, '+' | '-' | '*' | '/' | '^')
    }

    /// 中缀转后缀
    fn infix_to_postfix(&self, infix_expr: &str) -> MagicBoxResult<Vec<String>> {
        let mut number: Vec<char> = Vec::new();
        let mut output: Vec<String> = Vec::new();
        let mut stack: VecDeque<char> = VecDeque::new();

        for token in infix_expr.chars() {
            match token {
                '(' => stack.push_back(token),
                ')' => {
                    while let Some(top) = stack.pop_back() {
                        if top != '(' {
                            if !number.is_empty() {
                                // 将运算符压入结果栈之前，需要将搜集的数值字符转为字符串入结果栈
                                output.push(number.iter().collect::<String>());
                                // 重置数值字符
                                number.clear();
                            }

                            output.push(top.to_string());
                        } else {
                            break;
                        }
                    }
                }
                ch if self.is_operator(ch) => {
                    while let Some(top) = stack.back() {
                        if !stack.is_empty() && '(' != *top && self.precedence(*top)? >= self.precedence(ch)? {
                            if !number.is_empty() {
                                // 将运算符压入结果栈之前，需要将搜集的数值字符转为字符串入结果栈
                                output.push(number.iter().collect::<String>());
                                // 重置数值字符
                                number.clear();
                            }

                            output.push(stack.pop_back().unwrap().to_string());
                        } else {
                            break;
                        }
                    }

                    if !number.is_empty() {
                        // 将运算符压入栈中之前，需要将搜集的数值字符转为字符串入结果栈
                        output.push(number.iter().collect::<String>());
                        // 重置数值字符
                        number.clear();
                    }

                    // 运算符入栈
                    stack.push_back(ch);
                }
                _ => number.push(token), // 假设输入只包含数字和括号、基本算术运算符
            }
        }

        if !number.is_empty() {
            // 将运算符压入栈中之前，需要将搜集的数值字符转为字符串入结果栈
            output.push(number.iter().collect::<String>());
            // 重置数值字符
            number.clear();
        }

        while let Some(op) = stack.pop_back() {
            output.push(op.to_string());
        }

        Ok(output)
    }
}

mod tests {
    #[test]
    fn test_calc_command_infix_to_postfix() {
        println!("{:?}", super::CalcCommand::default().infix_to_postfix("32+15"));
        println!("{:?}", super::CalcCommand::default().infix_to_postfix("32-15"));
        println!("{:?}", super::CalcCommand::default().infix_to_postfix("32*15"));
        println!("{:?}", super::CalcCommand::default().infix_to_postfix("32/15"));
        println!("{:?}", super::CalcCommand::default().infix_to_postfix("32^2"));
        println!("{:?}", super::CalcCommand::default().infix_to_postfix("32*15+(1+2)^3"));
    }

    #[test]
    fn test_calc_command_calc_postfix_value() {
        let postfix_expr = vec!["32", "15", "*", "1", "2", "+", "3", "^", "+"].iter().map(|v| v.to_string()).collect::<Vec<String>>();

        println!("{:?}", super::CalcCommand::default().calc_postfix_value(&postfix_expr));
    }
}